﻿using EventMgrLib;
using Polenter.Serialization;
using SmartMotion.Core.Mgrs;
using Sunny.UI;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Drawing;
using System.Linq;
using System.Reflection;

namespace SmartMotion.Core
{
    public class ActionItem
    {
        protected readonly EventMgr Em;

        public ActionItem()
        {
            Em = EventMgr.Ins;

            ParaTypes = new List<string>();
            ParaNames = new List<string>();
            Parms = new List<MethodParms>();
            Nodes = new ActionItemConnection();
        }

        #region 属性

        public string Name { get; set; }

        /// <summary>
        /// Dll的文件名加扩展名
        /// </summary>
        public string Dll { get; set; }

        /// <summary>
        /// 工具名称
        /// </summary>
        public string TypeName { get; set; }

        /// <summary>
        /// 选择的方法名称
        /// </summary>
        public string MethodName { get; set; }

        /// <summary>
        /// 图标名称
        /// </summary>
        public string Icon { get; set; }

        /// <summary>
        /// 工具名称
        /// </summary>
        public string ItemName { get; set; }

        /// <summary>
        /// 分组名称
        /// </summary>
        public string Group { get; set; }

        /// <summary>
        /// 是否静态方法
        /// </summary>
        public bool IsStatic { get; set; }

        /// <summary>
        /// 返回值类型
        /// </summary>
        public string ReturnType { get; set; }

        /// <summary>
        /// 参数列表类型名
        /// </summary>
        public List<string> ParaTypes { get; set; }

        /// <summary>
        /// 参数名称
        /// </summary>
        public List<string> ParaNames { get; set; }

        /// <summary>
        /// 描述
        /// </summary>
        public string Description { get; set; }

        public List<MethodParms> Parms { get; set; }
        public ActionItemConnection Nodes { get; set; }

        /// <summary>
        /// 执行方法的对象名称
        /// </summary>
        public string ObjName { get; set; }

        /// <summary>
        /// 执行方法的对象GUID
        /// </summary>
        public string ObjGuid { get; set; }

        [Browsable(true), Description("执行方法的对象"), Category("程序集"), ReadOnly(true)]
        [ExcludeFromSerialization]
        public object Obj { get; set; }
        /// <summary>
        /// 返回值对象名称格式是 字典.分组.对象名称
        /// </summary>
        public string ReturnObjName { get; set; }
        public string ReturnObjGuid { get; set; } = Guid.NewGuid().ToString();

        /// <summary>
        /// 是否执行
        /// </summary>
        public bool InUse { get; set; } = true;

        /// <summary>
        /// 运行状态
        /// </summary>
        [ExcludeFromSerialization]
        public string State { get; set; } = "Ready";

        private Image _iconImage;

        [ExcludeFromSerialization]
        public Image IconImage
        {
            get
            {
                if (ToolMgr.Ins.Images.ContainsKey(Icon))
                {
                    _iconImage = ToolMgr.Ins.Images[Icon];
                }
                return _iconImage;
            }
        }

        /// <summary>
        /// 运行时间
        /// </summary>
        [ExcludeFromSerialization]
        public int Time { get; set; }

        #endregion 反射用的属性

        #region 方法

        public void IniState(ActionItemConnection nodes)
        {
            foreach (ActionItem actionItem in nodes)
            {
                actionItem.State = "Ready";
                Em.GetEvent<RunActionItem>().Publish(actionItem);
                if (actionItem.Nodes.Count>0)
                {
                    IniState(actionItem.Nodes);
                }
            }
        }

        public virtual ActionResult Run()
        {
            ActionResult result = ActionResult.Success;
            Stopwatch sw = Stopwatch.StartNew();
            State = "running...";
            Em.GetEvent<RunActionItem>().Publish(this);
            IniState(Nodes);
            result =RunMethod();
            if (Nodes.Count>0)
            {
                result = RunNodes();
            }
            State = result.ToString();   
            Time = (int) sw.ElapsedMilliseconds;
            Em.GetEvent<RunActionItem>().Publish(this);
            Em.GetEvent<DebugMessage>().Publish($"{MethodName}执行了一次,耗时{Time}");
            return result;

        }

        private ActionResult RunNodes()
        {
            ActionResult result = ActionResult.Success;
            foreach (ActionItem actionItem in Nodes)
            {
                result = actionItem.Run();
                if (result==ActionResult.Error)
                {
                    break;
                }
            }
            return result;
        }

        protected virtual ActionResult RunMethod()
        {
            // 返回值类型 返回值接收变量= 方法名(参数列表);
            //Class1 class1 = new Class1();
            //string returnVar = class1.非静态有参数("abcd");
            //参数可能为null，执行参数的对象可能为null，返回值可能是void，返回值可能不使用
            try
            {

                #region 准备执行方法的对象

                //如上面的class1
                object runObj = null;
                if (!string.IsNullOrEmpty(ObjName))
                {
                    var varInfo = VarMgr.Ins.GetVarByGuid(ObjGuid);
                    runObj = varInfo.Value;
                }

                #endregion 准备执行方法的对象

                #region 反射获得函数

                //如上面的非静态有参数
                var method = InitilizeMethod();
                if (method == null) throw new Exception("没有找到方法");

                #endregion 反射获得函数

                #region 准备参数列表

                var objs = new List<object>();//参数列表对象
                foreach (var item in Parms)
                {
                    object temp;

                    if (item.VarSelected)
                    {
                        var varInfo = VarMgr.Ins.GetVarByName(item.VarName);

                        temp = varInfo.Value;
                    }
                    else
                    {
                        //把手动输入的字符串转换为正确的类型
                        if (item.Type == typeof(int).FullName) { temp = Convert.ToInt32(item.VarName); }
                        else if (item.Type == typeof(uint).FullName) { temp = Convert.ToUInt32(item.VarName); }
                        else if (item.Type == typeof(short).FullName) { temp = Convert.ToInt16(item.VarName); }
                        else if (item.Type == typeof(ushort).FullName) { temp = Convert.ToUInt16(item.VarName); }
                        else if (item.Type == typeof(byte).FullName) { temp = Convert.ToByte(item.VarName); }
                        else if (item.Type == typeof(sbyte).FullName) { temp = Convert.ToSByte(item.VarName); }
                        else if (item.Type == typeof(long).FullName) { temp = Convert.ToInt64(item.VarName); }
                        else if (item.Type == typeof(ulong).FullName) { temp = Convert.ToUInt64(item.VarName); }
                        else if (item.Type == typeof(float).FullName) { temp = Convert.ToSingle(item.VarName); }
                        else if (item.Type == typeof(double).FullName) { temp = Convert.ToDouble(item.VarName); }
                        else if (item.Type == typeof(decimal).FullName) { temp = Convert.ToDecimal(item.VarName); }
                        else if (item.Type == typeof(bool).FullName) { temp = Convert.ToBoolean(item.VarName); }
                        else
                        {
                            temp = item.VarName;
                        }
                    }

                    if (temp != null)
                    {
                        objs.Add(temp);
                    }
                }

                object[] objArray = null;
                if (objs.Count > 0)
                {
                    objArray = objs.ToArray();
                }

                #endregion 准备参数列表

                #region 执行

                var result = method.Invoke(runObj, objArray);

                #endregion 执行

                #region 处理返回值

                if (!ReturnType.Contains("Void") && !string.IsNullOrEmpty(ReturnObjName))
                {
                    var varObj = VarMgr.Ins.GetVarByName(ReturnObjName);
                    varObj.Value = result;
                }

                #endregion 处理返回值
               return ActionResult.Success;
            }
            catch (Exception e)
            {
                Em.GetEvent<DebugMessage>().Publish($"运行{ItemName}发生异常{e.Message}");
                return ActionResult.Error;
            }
        }

        private MethodInfo InitilizeMethod()
        {
            string fileName = Environment.CurrentDirectory + "\\" + Dll;
            var curAssembly = Assembly.LoadFile(fileName);
            var type = curAssembly.GetType(TypeName);
            //var method = type.GetMethod(MethodName);//函数没有重载的时候用不会有问题，有重载就会有问题
            var method = type.GetMethod(MethodName, ParaTypes.Select(Type.GetType).ToArray());//方法名，参数类型列表
            return method;
        }

        public virtual bool Initilize()
        {
            return true;
        }

        public virtual UIPage GetParasPage()
        {
            return new FrmActionItem(this);
        }   

        public virtual UIForm GetConfigForm()
        {
            return null;
        }

        #endregion
    }

    public enum ActionResult
    {
        Success,
        Error,
        Break,
        Continue,
    }
}